home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / vfs / ftpfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  53.7 KB  |  2,311 lines

  1. /* Virtual File System: FTP file system.
  2.    Copyright (C) 1995 The Free Software Foundation
  3.    
  4.    Written by: 1995 Ching Hui
  5.                1995 Jakub Jelinek
  6.                1995 Miguel de Icaza
  7.    
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2 of the License, or
  11.    (at your option) any later version.
  12.    
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.    
  22. /* FTPfs TODO:
  23.  
  24. - make it more robust - all the connects etc. should handle EADDRINUSE and
  25.   ERETRY (have I spelled these names correctly?)
  26. - make the user able to flush a connection - all the caches will get empty
  27.   etc., (tarfs as well), we should give there a user selectable timeout
  28.   and assign a key sequence.  
  29. - use hash table instead of linklist to cache ftpfs directory.
  30. - complete rename operation.
  31.  */
  32.  
  33. #include <config.h>
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include <string.h>
  37. #include <unistd.h>
  38. #include <stdlib.h>
  39. #include <stdarg.h>
  40. #include <fcntl.h>
  41. #include <pwd.h>
  42. #include <time.h>
  43. #include <sys/types.h>
  44. #if defined(HAVE_UNISTD_H)
  45. #include <unistd.h>
  46. #endif
  47. #if IS_AIX
  48. #   include <sys/select.h>
  49. #endif
  50. #include "../src/fs.h"
  51. #include "../src/mad.h"
  52. #include "../src/setup.h"
  53. #include "../src/tty.h"        /* enable/disable interrupt key */
  54. #include <netdb.h>        /* struct hostent */
  55. #include <sys/socket.h>        /* AF_INET */
  56. #include <netinet/in.h>        /* struct in_addr */
  57. #ifdef HAVE_SETSOCKOPT
  58. #    include <netinet/ip.h>    /* IP options */
  59. #endif
  60. #include <arpa/inet.h>
  61. #include <arpa/ftp.h>
  62. #include <arpa/telnet.h>
  63. #include <sys/time.h>
  64. #include <sys/param.h>
  65.  
  66. #ifdef USE_TERMNET
  67. #include <termnet.h>
  68. #endif
  69.  
  70. #include "../src/mem.h"
  71. #define WANT_PARSE_LS_LGA
  72. #include "vfs.h"
  73. #include "tcputil.h"
  74. #include "../src/util.h"
  75. #include "../src/dialog.h"
  76. #include "container.h"
  77. #include "ftpfs.h"
  78. #ifndef MAXHOSTNAMELEN
  79. #    define MAXHOSTNAMELEN 64
  80. #endif
  81. #define UPLOAD_ZERO_LENGTH_FILE
  82.  
  83. void print_vfs_message(char *, ...);
  84.  
  85. static int ftpfserrno;
  86. static int code;
  87.  
  88. /* Delay to retry a connection */
  89. int ftpfs_retry_seconds = 30;
  90.  
  91. /* Use the ~/.netrc */
  92. int use_netrc = 1;
  93.  
  94. extern char *home_dir;
  95.  
  96. /* Anonymous setup */
  97. char *ftpfs_anonymous_passwd;
  98. int ftpfs_directory_timeout;
  99.  
  100. /* Proxy host */
  101. char *ftpfs_proxy_host = 0;
  102.  
  103. /* source routing host */
  104. extern int source_route;
  105.  
  106. /* If set, then log dialog between server and client */
  107. static int ftpfs_debug_server_dialog = 0;
  108.  
  109. /* Where we store the transactions */
  110. static FILE *ftpfs_logfile;
  111.  
  112. /* If true, the directory cache is forced to reload */
  113. static int force_expiration = 0;
  114.  
  115. struct linklist *ftpfs_connections_list;
  116.  
  117. extern char *last_current_dir;
  118.  
  119. /* command wait_flag: */
  120. #define NONE        0x00
  121. #define WAIT_REPLY  0x01
  122. #define WANT_STRING 0x02
  123. char reply_str [80];
  124.  
  125. static char *ftpfs_get_current_directory(struct ftpfs_connection *bucket);
  126.  
  127. /* Extract the hostname and username from the path */
  128. /* path is in the form: [user@]hostname:port/remote-dir, e.g.:
  129.  * ftp://sunsite.unc.edu/pub/linux
  130.  * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
  131.  * ftp://tsx-11.mit.edu:8192/
  132.  * ftp://joe@foo.edu:11321/private
  133.  * If the user is empty, e.g. ftp://@roxanne/private, then your login name
  134.  * is supplied.
  135.  * */
  136.  
  137. char *ftpfs_get_host_and_username (char *path, char **host, char **user, int *port, char **pass)
  138. {
  139.     return get_host_and_username (path, host, user, port, 21, 1, pass);
  140. }
  141.  
  142. static int
  143. get_line (int sock, char *buf, int buf_len)
  144. {
  145.     int i, status;
  146.     char c;
  147.  
  148.     for (i = 0; i < buf_len; i++, buf++) {
  149.     if (read(sock, buf, sizeof(char)) <= 0)
  150.         return 0;
  151.     if (ftpfs_debug_server_dialog){
  152.         fwrite (buf, 1, 1, ftpfs_logfile);
  153.         fflush (ftpfs_logfile);
  154.     }
  155.     if (*buf == '\n') {
  156.         *buf = 0;
  157.         return 1;
  158.     }
  159.     }
  160.     *buf = 0;
  161.     while ((status = read(sock, &c, sizeof(c))) > 0){
  162.     if (ftpfs_debug_server_dialog){
  163.         fwrite (&c, 1, 1, ftpfs_logfile);
  164.         fflush (ftpfs_logfile);
  165.     }
  166.     if (c == '\n')
  167.         return 1;
  168.     }
  169.     return 0;
  170. }
  171.  
  172. /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
  173. int getreply (int sock, char *string_buf, int string_len)
  174. {
  175.     char answer[1024];
  176.     int i;
  177.     
  178.     for (;;) {
  179.         if (!get_line(sock, answer, sizeof(answer))) {
  180.         if (string_buf)
  181.         *string_buf = 0;
  182.         code = 421;
  183.         return 4;
  184.     }
  185.     switch(sscanf(answer, "%d", &code)) {
  186.         case 0:
  187.             if (string_buf) {
  188.             strncpy(string_buf, answer, string_len - 1);
  189.             *(string_buf + string_len - 1) = 0;
  190.         }
  191.             code = 500;
  192.             return 5;
  193.         case 1:
  194.          if (answer[3] == '-') {
  195.             while (1) {
  196.             if (!get_line(sock, answer, sizeof(answer))) {
  197.                 if (string_buf)
  198.                 *string_buf = 0;
  199.                 code = 421;
  200.                 return 4;
  201.             }
  202.             if ((sscanf(answer, "%d", &i) > 0) && 
  203.                 (code == i) && (answer[3] == ' '))
  204.                 break;
  205.             }
  206.         }
  207.             if (string_buf) {
  208.             strncpy(string_buf, answer, string_len - 1);
  209.             *(string_buf + string_len - 1) = 0;
  210.         }
  211.         return code / 100;
  212.     }
  213.     }
  214. }
  215.  
  216. static void
  217. ftpentry_destructor(void *data)
  218. {
  219.     struct ftpentry *fe = data;
  220.     
  221.     fe->count--;
  222.     if (fe->count > 0)
  223.         return;
  224.     free(fe->name);
  225.     if (fe->linkname)
  226.     free(fe->linkname);
  227.     if (fe->local_filename) {
  228.         if (fe->local_is_temp) {
  229.             if (!fe->local_stat.st_mtime)
  230.             unlink(fe->local_filename);
  231.         else {
  232.             struct stat sb;
  233.             
  234.             if (stat (fe->local_filename, &sb) >=0 && 
  235.                 fe->local_stat.st_mtime == sb.st_mtime)
  236.                 unlink (fe->local_filename); /* Delete only if it hasn't changed */
  237.         }
  238.     }
  239.     free(fe->local_filename);
  240.     fe->local_filename = 0;
  241.     }
  242.     if (fe->remote_filename)
  243.     free(fe->remote_filename);
  244.     if (fe->l_stat)
  245.     free(fe->l_stat);
  246.     free(fe);
  247. }
  248.  
  249. static void
  250. ftpfs_dir_destructor(void *data)
  251. {
  252.     struct ftpfs_dir *fd = data;
  253.  
  254.     fd->count--;
  255.     if (fd->count > 0) 
  256.     return;
  257.     free(fd->remote_path);
  258.     linklist_destroy(fd->file_list, ftpentry_destructor);
  259.     free(fd);
  260. }
  261.  
  262. static int command (struct ftpfs_connection *bucket, int wait_reply,
  263.             char *fmt, ...)
  264. {
  265.     va_list ap;
  266.     char buf[2048]; /* FIXME: buffer exceed ?? */
  267.     int n, status;
  268.     int sock = qsock (bucket);
  269.     
  270.     va_start (ap, fmt);
  271.     vsprintf (buf, fmt, ap);
  272.     va_end (ap);
  273.     n = strlen(buf);
  274.     buf[n++] = '\r';
  275.     buf[n++] = '\n';
  276.     buf[n] = 0;
  277.  
  278.     if (ftpfs_debug_server_dialog){
  279.     fwrite (buf, strlen (buf), 1, ftpfs_logfile);
  280.     fflush (ftpfs_logfile);
  281.     }
  282.     got_sigpipe = 0;
  283.     enable_interrupt_key();
  284.     status = write(sock, buf, strlen(buf));
  285.     disable_interrupt_key();
  286.     
  287.     if (status < 0){
  288.     disable_interrupt_key();
  289.     code = 421;
  290.     if (errno == EPIPE)
  291.         got_sigpipe = 1;
  292.     return TRANSIENT;
  293.     }
  294.     if (wait_reply)
  295.     return getreply (sock, (wait_reply & WANT_STRING) ? reply_str : NULL, sizeof (reply_str)-1);
  296.     return COMPLETE;
  297. }
  298.  
  299. static void
  300. ftpfs_connection_close (void *data)
  301. {
  302.     struct ftpfs_connection *bucket = data;
  303.  
  304.     print_vfs_message ("ftpfs: Disconnecting from %s", qhost(bucket));
  305.     command(bucket, WAIT_REPLY, "QUIT");
  306.     close(qsock(bucket));
  307. }
  308.  
  309. static void
  310. ftpfs_free_bucket (void *data)
  311. {
  312.     struct ftpfs_connection *bucket = data;
  313.  
  314.     free(qhost(bucket));
  315.     free(quser(bucket));
  316.     if (qcdir(bucket))
  317.     free(qcdir(bucket));
  318.     if (qhome(bucket))
  319.         free(qhome(bucket));
  320.     if (qupdir(bucket))
  321.         free(qupdir(bucket));
  322.     linklist_destroy(qdcache(bucket), ftpfs_dir_destructor);
  323.     free(bucket);
  324. }
  325.  
  326. static void
  327. ftpfs_connection_destructor(void *data)
  328. {
  329.     ftpfs_connection_close (data);
  330.     ftpfs_free_bucket (data);
  331. }
  332.  
  333. static int
  334. changetype (struct ftpfs_connection *bucket, int binary)
  335. {
  336.     static int curr_binary = -1;
  337.     
  338.     if (binary != curr_binary) {
  339.         if (command (bucket, WAIT_REPLY, "TYPE %c", binary ? 'I' : 'A') != COMPLETE) {
  340.         ftpfserrno = EIO;
  341.             return -1;
  342.     }
  343.         curr_binary = binary;
  344.     }
  345.     return binary;
  346. }
  347.  
  348. inline void
  349. flush_all_directory(struct ftpfs_connection *bucket)
  350. {
  351.     linklist_delete_all(qdcache(bucket), ftpfs_dir_destructor);
  352.  
  353. }
  354.  
  355. /* This routine logs the user in */
  356. static int 
  357. login_server (struct ftpfs_connection *bucket, char *netrcpass)
  358. {
  359.     char *pass;
  360.     char *name;            /* login user name */
  361.     
  362.     if (netrcpass)
  363.         pass = strdup (netrcpass);
  364.     else {
  365.         if (!strcmp (quser(bucket), "anonymous") || 
  366.             !strcmp (quser(bucket), "ftp"))
  367.         pass = strdup(ftpfs_anonymous_passwd);
  368.         else {
  369.             char *p;
  370.  
  371.         p = copy_strings (" FTP: Password required for ", quser(bucket), 
  372.                   " ", NULL);
  373.             pass = input_dialog (p, "Password:", "");
  374.             free (p);
  375.             if (pass == NULL) {
  376.             ftpfserrno = EPERM;
  377.                 return 0;
  378.             }
  379.         }
  380.     }
  381.     
  382.     /* Proxy server accepts: username@host-we-want-to-connect*/
  383.     if (qproxy (bucket)){
  384.     /* qhost(bucket) has: "!hostname" */
  385.     name = copy_strings (quser(bucket), "@", qhost(bucket)+1, 0);
  386.     } else 
  387.     name = strdup (quser (bucket));
  388.     
  389.     if (getreply (qsock(bucket), NULL, 0) == COMPLETE) {
  390.     print_vfs_message("ftpfs: sending login name");
  391.         if ((code = command (bucket, WAIT_REPLY, "USER %s", name)) == CONTINUE) {
  392.         print_vfs_message("ftpfs: sending user password");
  393.             if (command (bucket, WAIT_REPLY, "PASS %s", pass) == COMPLETE)
  394.             {
  395.             print_vfs_message("ftpfs: logged in");
  396.             wipe_password (pass);
  397.             free (name);
  398.             return 1;
  399.         }
  400.     } else {
  401.         bucket->failed_on_login = 1;
  402.  
  403.         /* This matches the end of the code below, just to make it
  404.          * obvious to the optimizer
  405.          */
  406.         wipe_password (pass);
  407.         free (name);
  408.         return 0;
  409.     }
  410.     }
  411.     print_vfs_message ("ftpfs: Login incorrect for user %s ", quser(bucket));
  412.     ftpfserrno = EPERM;
  413.     wipe_password (pass);
  414.     free (name);
  415.     return 0;
  416. }
  417.  
  418. #ifdef HAVE_SETSOCKOPT
  419. static void
  420. setup_source_route (int socket, int dest)
  421. {
  422.     char buffer [20];
  423.     char *ptr = buffer;
  424.  
  425.     if (!source_route)
  426.     return;
  427.     bzero (buffer, sizeof (buffer));
  428.     *ptr++ = IPOPT_LSRR;
  429.     *ptr++ = 3 + 8;
  430.     *ptr++ = 4;            /* pointer */
  431.  
  432.     /* First hop */
  433.     bcopy ((char *) &source_route, ptr, sizeof (int));
  434.     ptr += 4;
  435.  
  436.     /* Second hop (ie, final destination) */
  437.     bcopy ((char *) &dest, ptr, sizeof (int));
  438.     ptr += 4;
  439.     while ((ptr - buffer) & 3)
  440.     ptr++;
  441.     if (setsockopt (socket, IPPROTO_IP, IP_OPTIONS,
  442.             buffer, ptr - buffer) < 0)
  443.     message (1, " Error ", " Could not set source routing (%s)", unix_error_string (errno));
  444. }
  445. #else
  446. #define setup_source_route(x,y)
  447. #endif
  448.     
  449. static int
  450. ftpfs_open_socket(struct ftpfs_connection *bucket)
  451. {
  452.     struct   sockaddr_in server_address;
  453.     struct   hostent *hp;
  454.     int      my_socket;
  455.     char     *host;
  456.  
  457.     /* Use a proxy host? */
  458.     host = qhost(bucket);
  459.  
  460.     if (!host || !*host){
  461.     print_vfs_message ("ftpfs: Invalid host name.");
  462.     return -1;
  463.     }
  464.  
  465.     /* Hosts to connect to that start with a ! should use proxy */
  466.     if (*host == '!' && ftpfs_proxy_host){
  467.     bucket->use_proxy = 1;
  468.     host = ftpfs_proxy_host;
  469.     }
  470.     
  471.     /* Get host address */
  472.     bzero ((char *) &server_address, sizeof (server_address));
  473.     server_address.sin_family = AF_INET;
  474.     server_address.sin_addr.s_addr = inet_addr (host);
  475.     if (server_address.sin_addr.s_addr != -1)
  476.     server_address.sin_family = AF_INET;
  477.     else {
  478.     hp = gethostbyname(host);
  479.     if (hp == NULL){
  480.         print_vfs_message("ftpfs: Invalid host address.");
  481.         ftpfserrno = EINVAL;
  482.         return -1;
  483.     }
  484.     server_address.sin_family = hp->h_addrtype;
  485.     bcopy ((char *) hp->h_addr, (char *) &server_address.sin_addr,
  486.            hp->h_length);
  487.     }
  488.  
  489.     server_address.sin_port = htons (qport(bucket));
  490.  
  491.     /* Connect */
  492.     if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  493.     ftpfserrno = errno;
  494.     return -1;
  495.     }
  496.     setup_source_route (my_socket, server_address.sin_addr.s_addr);
  497.     
  498.     print_vfs_message("ftpfs: making connection to %s", host);
  499.  
  500.     enable_interrupt_key(); /* clear the interrupt flag */
  501.  
  502.     if (connect (my_socket, (struct sockaddr *) &server_address,
  503.          sizeof (server_address)) < 0){
  504.     ftpfserrno = errno;
  505.     if (errno == EINTR && got_interrupt())
  506.         print_vfs_message("ftpfs: connection interrupted by user");
  507.     else
  508.         print_vfs_message("ftpfs: connection to server failed: %s",
  509.                   unix_error_string(errno));
  510.     disable_interrupt_key();
  511.     close (my_socket);
  512.     return -1;
  513.     }
  514.     disable_interrupt_key();
  515.     return my_socket;
  516. }
  517.  
  518. static struct ftpfs_connection *
  519. open_command_connection (char *host, char *user, int port, char *netrcpass)
  520. {
  521.     struct ftpfs_connection *bucket;
  522.     int retry_seconds, count_down;
  523.  
  524.     bucket = xmalloc(sizeof(struct ftpfs_connection), 
  525.              "struct ftpfs_connection");
  526.     
  527.     if (bucket == NULL) {
  528.     ftpfserrno = ENOMEM;
  529.     return NULL;
  530.     }
  531.     qhost(bucket) = host;
  532.     quser(bucket) = user;
  533.     qcdir(bucket) = NULL;
  534.     qport(bucket) = port;
  535.     qlock(bucket) = 0;
  536.     qhome(bucket) = NULL;
  537.     qproxy(bucket)= 0;
  538.     qupdir(bucket)= 0;
  539.     qdcache(bucket)=0;
  540.     bucket->lock = 0;
  541.     bucket->use_proxy = 0;
  542.     bucket->use_source_route = source_route;
  543.     retry_seconds = 0;
  544.     
  545.     if ((qdcache(bucket) = linklist_init()) == NULL) {
  546.     ftpfserrno = ENOMEM;
  547.     free(host);
  548.     free(user);
  549.     free(bucket);
  550.     return NULL;
  551.     }
  552.     
  553.     do { 
  554.     bucket->failed_on_login = 0;
  555.  
  556.     qsock(bucket) = ftpfs_open_socket(bucket);
  557.     if (qsock(bucket) == -1)  {
  558.         ftpfs_free_bucket (bucket);
  559.         return NULL;
  560.     }
  561.  
  562.     if (!login_server(bucket, netrcpass)) {
  563.         if (!bucket->failed_on_login){
  564.         ftpfs_connection_destructor (bucket);
  565.         return NULL;
  566.         }
  567.         if (ftpfs_retry_seconds){
  568.         retry_seconds = ftpfs_retry_seconds;
  569.         enable_interrupt_key ();
  570.         for (count_down = retry_seconds; count_down; count_down--){
  571.             print_vfs_message ("Waiting to retry... %d\n", count_down);
  572.             sleep (1);
  573.             if (got_interrupt ()){
  574.             retry_seconds = 0;
  575.             break;
  576.             }
  577.         }
  578.         disable_interrupt_key ();
  579.         }
  580.     }
  581.     } while (retry_seconds);
  582.     
  583.     qhome(bucket) = ftpfs_get_current_directory (bucket);
  584.     if (!qhome(bucket))
  585.         qhome(bucket) = strdup ("/");
  586.     if (last_current_dir) {
  587.         if (last_current_dir [strlen (last_current_dir) - 1] == '/')
  588.             qupdir(bucket) = strdup (last_current_dir);
  589.         else
  590.             qupdir(bucket) = copy_strings (last_current_dir, "/", NULL);
  591.     } else
  592.         qupdir(bucket) = strdup ("/");
  593.     return bucket;
  594. }
  595.  
  596. static int
  597. is_connection_closed(struct ftpfs_connection *bucket)
  598. {
  599.     struct fd_set rset;
  600.     struct timeval t;
  601.  
  602.     if (got_sigpipe)
  603.     return 1;
  604.     t.tv_sec = 0;
  605.     t.tv_usec = 0;
  606.     FD_ZERO(&rset);
  607.     FD_SET(qsock(bucket), &rset);
  608.     while (1) {
  609.     if (select(qsock(bucket) + 1, &rset, NULL, NULL, &t) < 0)
  610.         if (errno != EINTR)
  611.         return 1;
  612.     return 0;
  613. #if 0
  614.     if (FD_ISSET(qsock(bucket), &rset)) {
  615.         n = read(qsock(bucket), &read_ahead, sizeof(read_ahead));
  616.         if (n <= 0) 
  617.         return 1;
  618.     }     else
  619. #endif
  620.     }
  621. }
  622.  
  623. /* This routine keeps track of open connections */
  624. /* Returns a connected socket to host */
  625. static struct ftpfs_connection *
  626. ftpfs_open_link (char *host, char *user, int port, char *netrcpass)
  627. {
  628.     int sock;
  629.     struct ftpfs_connection *bucket;
  630.     struct linklist *lptr;
  631.     
  632.     for (lptr = ftpfs_connections_list->next; 
  633.      lptr != ftpfs_connections_list; lptr = lptr->next) {
  634.     bucket = lptr->data;
  635.     if ((strcmp (host, qhost(bucket)) == 0) &&
  636.         (strcmp (user, quser(bucket)) == 0) &&
  637.         (port == qport(bucket))) {
  638.         free(host);
  639.         free(user);
  640.         
  641.         /* check the connection is closed or not, just hack */
  642.         if (is_connection_closed(bucket)) {
  643.         flush_all_directory(bucket);
  644.         sock = ftpfs_open_socket(bucket);
  645.         if (sock != -1) {
  646.             close(qsock(bucket));
  647.             qsock(bucket) = sock;
  648.             if (login_server(bucket, netrcpass))
  649.             return bucket;
  650.         } 
  651.         
  652.         /* connection refused */
  653.         lptr->prev->next = lptr->next;
  654.         lptr->next->prev = lptr->prev;
  655.         ftpfs_connection_destructor(bucket);
  656.         return NULL;
  657.         }
  658.         return bucket;
  659.     }
  660.     }
  661.     bucket = open_command_connection(host, user, port, netrcpass);
  662.     if (bucket == NULL)
  663.     return NULL;
  664.     if (!linklist_insert(ftpfs_connections_list, bucket)) {
  665.     ftpfs_connection_destructor(bucket);
  666.     return NULL;
  667.     }
  668.     return bucket;
  669. }
  670.  
  671. /* The returned directory should always contain a trailing slash */
  672. static char *ftpfs_get_current_directory(struct ftpfs_connection *bucket)
  673. {
  674.     char buf[4096], *bufp, *bufq;
  675.  
  676.     if (command(bucket, NONE, "PWD") != COMPLETE)
  677.     return NULL;
  678.     if (getreply(qsock(bucket), buf, sizeof(buf)) == COMPLETE) {
  679.         bufp = NULL;
  680.     for (bufq = buf; *bufq; bufq++)
  681.         if (*bufq == '"') {
  682.             if (!bufp) {
  683.             bufp = bufq + 1;
  684.             } else {
  685.             *bufq = 0;
  686.             if (*bufp) {
  687.                 if (*(bufq - 1) != '/') {
  688.                     *bufq++ = '/';
  689.                     *bufq = 0;
  690.                 }
  691.                 return strdup (bufp);
  692.             } else {
  693.                 ftpfserrno = EIO;
  694.                 return NULL;
  695.             }
  696.         }
  697.         }
  698.     }
  699.     ftpfserrno = EIO;
  700.     return NULL;
  701. }
  702.  
  703. void ftpfs_fill_names (void (*func)(char *))
  704. {
  705.     struct linklist *lptr;
  706.     char   *path_name;
  707.     struct ftpfs_connection *bucket;
  708.     
  709.     if (!ftpfs_connections_list)
  710.     return;
  711.     lptr = ftpfs_connections_list;
  712.     do {
  713.     if ((bucket = lptr->data) != 0){
  714.  
  715.         path_name = copy_strings ("ftp://", quser (bucket),
  716.                       "@",      qhost (bucket), 
  717.                       qcdir(bucket), 0);
  718.         (*func)(path_name);
  719.         free (path_name);
  720.     }
  721.     lptr = lptr->next;
  722.     } while (lptr != ftpfs_connections_list);
  723. }
  724.  
  725.     
  726. /* Setup Passive ftp connection, we use it for source routed connections */
  727. static int
  728. setup_passive (int my_socket, struct ftpfs_connection *bucket, struct sockaddr_in *sa)
  729. {
  730.     int xa, xb, xc, xd, xe, xf;
  731.     char n [6];
  732.     char *c = reply_str;
  733.     
  734.     if (command (bucket, WAIT_REPLY | WANT_STRING, "PASV") != COMPLETE)
  735.     return 0;
  736.  
  737.     /* Parse remote parameters */
  738.     for (c = reply_str + 4; (*c) && (!isdigit (*c)); c++)
  739.     ;
  740.     if (!*c)
  741.     return 0;
  742.     if (!isdigit (*c))
  743.     return 0;
  744.     if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
  745.     return 0;
  746.     n [0] = (unsigned char) xa;
  747.     n [1] = (unsigned char) xb;
  748.     n [2] = (unsigned char) xc;
  749.     n [3] = (unsigned char) xd;
  750.     n [4] = (unsigned char) xe;
  751.     n [5] = (unsigned char) xf;
  752.  
  753.     bcopy ((void *)n,     &(sa->sin_addr.s_addr), 4);
  754.     bcopy ((void *)&n[4], &(sa->sin_port), 2);
  755.     setup_source_route (my_socket, sa->sin_addr.s_addr);
  756.     if (connect (my_socket, (struct sockaddr *) sa, sizeof (struct sockaddr_in)) < 0)
  757.     return 0;
  758.     return 1;
  759. }
  760.  
  761. static int
  762. initconn (struct ftpfs_connection *bucket)
  763. {
  764.     struct sockaddr_in data_addr;
  765.     int data, len = sizeof(data_addr);
  766.     struct protoent *pe;
  767.  
  768.     getsockname(qsock(bucket), (struct sockaddr *) &data_addr, &len);
  769.     data_addr.sin_port = 0;
  770.     
  771.     pe = getprotobyname("tcp");
  772.     if (pe == NULL) {
  773.     ftpfserrno = EIO;
  774.     return -1;
  775.     }
  776.     data = socket (AF_INET, SOCK_STREAM, pe->p_proto);
  777.     if (data < 0) {
  778.     ftpfserrno = EIO;
  779.         return -1;
  780.     }
  781.  
  782.     if (bucket->use_source_route){
  783.     int c;
  784.     
  785.     if ((c = setup_passive (data, bucket, &data_addr)))
  786.         return data;
  787.     print_vfs_message("ftpfs: could not setup passive mode for source routing");
  788.     bucket->use_source_route = 0;
  789.     }
  790.     /* If passive setup fails, fallback to active connections */
  791.     /* Active FTP connection */
  792.     if (bind (data, (struct sockaddr *)&data_addr, len) < 0)
  793.     goto error_return;
  794.     getsockname(data, (struct sockaddr *) &data_addr, &len);
  795.     if (listen (data, 1) < 0)
  796.     goto error_return;
  797.     {
  798.     unsigned char *a = (unsigned char *)&data_addr.sin_addr;
  799.     unsigned char *p = (unsigned char *)&data_addr.sin_port;
  800.     
  801.     if (command (bucket, WAIT_REPLY, "PORT %d,%d,%d,%d,%d,%d", a[0], a[1], 
  802.              a[2], a[3], p[0], p[1]) != COMPLETE)
  803.         goto error_return;
  804.     }
  805.     return data;
  806. error_return:
  807.     close(data);
  808.     ftpfserrno = EIO;
  809.     return -1;
  810. }
  811.  
  812. static int
  813. open_data_connection (struct ftpfs_connection *bucket, char *cmd, char *remote, 
  814.         int isbinary)
  815. {
  816.     struct sockaddr_in from;
  817.     int s, j, data, fromlen = sizeof(from);
  818.     
  819.     if ((s = initconn (bucket)) == -1)
  820.         return -1;
  821.     if (changetype (bucket, isbinary) == -1)
  822.         return -1;
  823.     if (remote)
  824.         j = command (bucket, WAIT_REPLY, "%s %s", cmd, remote);
  825.     else
  826.         j = command (bucket, WAIT_REPLY, "%s", cmd);
  827.     if (j != PRELIM) {
  828.     ftpfserrno = EPERM;
  829.         return -1;
  830.     }
  831.     enable_interrupt_key();
  832.     if (bucket->use_source_route)
  833.     data = s;
  834.     else {
  835.     data = accept (s, (struct sockaddr *)&from, &fromlen);
  836.     if (data < 0) {
  837.         ftpfserrno = errno;
  838.         close(s);
  839.         return -1;
  840.     }
  841.     close(s);
  842.     } 
  843.     disable_interrupt_key();
  844.     return data;
  845. }
  846.  
  847. static char *ftpfs_get_path (struct ftpfs_connection **bucket, char *path)
  848. {
  849.     char *user, *host, *remote_path, *pass;
  850.     int port;
  851.  
  852.     /* An absolute path name, try to determine connection socket */
  853.     if (strncmp (path, "ftp://", 6) == 0){
  854.     path += 6;
  855.  
  856.     if (!(remote_path = ftpfs_get_host_and_username (path, &host, &user, 
  857.         &port, &pass))) {
  858.         ftpfserrno = ENOENT;
  859.         return NULL;
  860.     }
  861.     if ((*bucket = ftpfs_open_link (host, user, port, pass)) == NULL) {
  862.         free (remote_path);
  863.         if (pass)
  864.             wipe_password (pass);
  865.         return NULL;
  866.     }
  867.     if (pass)
  868.         wipe_password (pass);
  869.     return remote_path;
  870.     }
  871.     /* never get here !!! */
  872.     message(1, " Error ", " Oops, you just hit a bug in the code ");
  873.     return NULL;
  874. }
  875.  
  876. static void
  877. ftpfs_abort (struct ftpfs_connection *bucket, int dsock)
  878. {
  879.     static unsigned char ipbuf[3] = { IAC, IP, IAC };
  880.     fd_set mask;
  881.     char buf[1024];
  882.  
  883.     print_vfs_message("ftpfs: aborting transfer.");
  884.     if (send(qsock(bucket), ipbuf, sizeof(ipbuf), MSG_OOB) != sizeof(ipbuf)) {
  885.     print_vfs_message("ftpfs: abort error: %s", unix_error_string(errno));
  886.     return;
  887.     }
  888.     
  889.     if (command(bucket, NONE, "%cABOR", DM) != COMPLETE){
  890.     print_vfs_message ("ftpfs: abort failed");
  891.     return;
  892.     }
  893.     if (dsock != -1) {
  894.     FD_ZERO(&mask);
  895.     FD_SET(dsock, &mask);
  896.     if (select(dsock + 1, &mask, NULL, NULL, NULL) > 0)
  897.         while (read(dsock, buf, sizeof(buf)) > 0);
  898.     }
  899.     if ((getreply(qsock(bucket), NULL, 0) == TRANSIENT) && (code == 426))
  900.     getreply(qsock(bucket), NULL, 0);
  901. }
  902.  
  903. static void
  904. resolve_symlink(struct ftpfs_connection *bucket, struct ftpfs_dir *dir)
  905. {
  906.     char  buffer[2048] = "", *filename;
  907.     int sock;
  908.     FILE *fp;
  909.     struct stat s;
  910.     struct linklist *flist;
  911.     struct ftpentry *fe;
  912.     
  913.     print_vfs_message("Resolving symlink...");
  914.     
  915.     sock = open_data_connection (bucket, "LIST -lLa", 
  916.                  dir->remote_path, 0);
  917.     if (sock == -1) {
  918.     print_vfs_message("ftpfs: couldn't resolve symlink");
  919.     return;
  920.     }
  921.     
  922.     fp = fdopen(sock, "r");
  923.     if (fp == NULL) {
  924.     close(sock);
  925.     print_vfs_message("ftpfs: couldn't resolve symlink");
  926.     return;
  927.     }
  928.     enable_interrupt_key();
  929.     flist = dir->file_list->next;
  930.     while (1) {
  931.     do {
  932.         if (flist == dir->file_list)
  933.         goto done;
  934.         fe = flist->data;
  935.         flist = flist->next;
  936.     } while (!S_ISLNK(fe->s.st_mode));
  937.     while (1) {
  938.         if (parse_ls_lga (buffer, &s, &filename, NULL)) {
  939.         int r = strcmp(fe->name, filename);
  940.         free(filename);
  941.         if (r == 0) {
  942.             fe->l_stat = xmalloc(sizeof(struct stat), 
  943.                      "resolve_symlink: struct stat");
  944.             if (fe->l_stat == NULL)
  945.             goto done;
  946.             *fe->l_stat = s;
  947.             break;
  948.         }
  949.         if (r < 0)
  950.             break;
  951.         }
  952.         if (fgets (buffer, sizeof (buffer), fp) == NULL)
  953.         goto done;
  954.     }
  955.     }
  956. done:
  957.     while (fgets(buffer, sizeof(buffer), fp) != NULL);
  958.     disable_interrupt_key();
  959.     fclose(fp);
  960.     getreply(qsock(bucket), NULL, 0);
  961. }
  962.  
  963.  
  964. static struct ftpfs_dir *
  965. retrieve_dir(struct ftpfs_connection *bucket, char *remote_path)
  966. {
  967.     FILE *fp;
  968.     int sock, has_symlinks;
  969.     struct linklist *file_list, *p;
  970.     struct ftpentry *fe;
  971.     char buffer[8192];
  972.     struct ftpfs_dir *dcache;
  973.     int got_intr = 0;
  974.  
  975.     for (p = qdcache(bucket)->next;p != qdcache(bucket);
  976.      p = p->next) {
  977.     dcache = p->data;
  978.     if (strcmp(dcache->remote_path, remote_path) == 0) {
  979.         struct timeval tim;
  980.  
  981.         gettimeofday(&tim, NULL);
  982.         if ((tim.tv_sec < dcache->timestamp.tv_sec) && !force_expiration)
  983.         return dcache;
  984.         else {
  985.         force_expiration = 0;
  986.         p->next->prev = p->prev;
  987.         p->prev->next = p->next;
  988.         ftpfs_dir_destructor(dcache);
  989.         break;
  990.         }
  991.     }
  992.     }
  993.  
  994.     has_symlinks = 0;
  995.     print_vfs_message("ftpfs: Reading FTP directory...");
  996.     if (command(bucket, WAIT_REPLY, "CWD %s", remote_path) != COMPLETE) {
  997.     ftpfserrno = ENOENT;
  998.     print_vfs_message("ftpfs: CWD failed.");
  999.     return NULL;
  1000.     }
  1001.      
  1002.     file_list = linklist_init();
  1003.     if (file_list == NULL) {
  1004.     ftpfserrno = ENOMEM;
  1005.     print_vfs_message("ftpfs: couldn't get a file listing");
  1006.         return NULL;
  1007.     }
  1008.     dcache = xmalloc(sizeof(struct ftpfs_dir), 
  1009.              "struct ftpfs_dir");
  1010.     if (dcache == NULL) {
  1011.     ftpfserrno = ENOMEM;
  1012.     linklist_destroy(file_list, NULL);
  1013.     print_vfs_message("ftpfs: FAIL");
  1014.     return NULL;
  1015.     }
  1016.     gettimeofday(&dcache->timestamp, NULL);
  1017.     dcache->timestamp.tv_sec += ftpfs_directory_timeout;
  1018.     dcache->file_list = file_list;
  1019.     dcache->remote_path = strdup(remote_path);
  1020.     dcache->count = 1;
  1021.     sock = open_data_connection (bucket, "LIST -la", ".", 0);
  1022.     if (sock == -1)
  1023.     goto error_3;
  1024.     fp = fdopen(sock, "r");
  1025.     if (fp == NULL) {
  1026.     close(sock);
  1027.         goto error_2;
  1028.     }
  1029.  
  1030.     /* Clear the interrupt flag */
  1031.     enable_interrupt_key ();
  1032.     
  1033.     errno = 0;
  1034.     while (fgets (buffer, sizeof (buffer), fp) != NULL) {
  1035.  
  1036.     if (got_intr = got_interrupt ())
  1037.         break;
  1038.     
  1039.     fe = xmalloc(sizeof(struct ftpentry), "struct ftpentry");
  1040.     fe->freshly_created = 0;
  1041.     if (fe == NULL) {
  1042.         ftpfserrno = ENOMEM;
  1043.         goto error_1;
  1044.     }
  1045.         if (parse_ls_lga (buffer, &fe->s, &fe->name, &fe->linkname)) {
  1046.         fe->count = 1;
  1047.         fe->local_filename = fe->remote_filename = NULL;
  1048.         fe->l_stat = NULL;
  1049.         fe->bucket = bucket;
  1050.         if (S_ISLNK(fe->s.st_mode))
  1051.         has_symlinks = 1;
  1052.         if (!linklist_insert(file_list, fe)) {
  1053.         free(fe);
  1054.         ftpfserrno = ENOMEM;
  1055.             goto error_1;
  1056.         }
  1057.     }
  1058.     else
  1059.         free(fe);
  1060.     }
  1061.     if (got_intr){
  1062.     disable_interrupt_key();
  1063.     print_vfs_message("ftpfs: reading FTP directory interrupt by user");
  1064.     ftpfs_abort(bucket, fileno(fp));
  1065.     fclose(fp);
  1066.     ftpfserrno = EINTR;
  1067.     goto error_3;
  1068.     }
  1069.     fclose(fp);
  1070.     disable_interrupt_key();
  1071.     if (getreply (qsock (bucket), NULL, 0) != COMPLETE) {
  1072.     ftpfserrno = EIO;
  1073.         goto error_3;
  1074.     }
  1075.     if (file_list->next == file_list) {
  1076.     ftpfserrno = EACCES;
  1077.     goto error_3;
  1078.     }
  1079.     if (!linklist_insert(qdcache(bucket), dcache)) {
  1080.     ftpfserrno = ENOMEM;
  1081.         goto error_3;
  1082.     }
  1083.     if (has_symlinks)
  1084.     resolve_symlink(bucket, dcache);
  1085.     print_vfs_message("ftpfs: got listing");
  1086.     return dcache;
  1087. error_1:
  1088.     disable_interrupt_key();
  1089.     fclose(fp);
  1090. error_2:
  1091.     getreply(qsock(bucket), NULL, 0);
  1092. error_3:
  1093.     free(dcache->remote_path);
  1094.     free(dcache);
  1095.     linklist_destroy(file_list, ftpentry_destructor);
  1096.     print_vfs_message("ftpfs: failed");
  1097.     return NULL;
  1098. }
  1099.  
  1100. static int
  1101. store_file(struct ftpentry *fe)
  1102. {
  1103.     int local_handle, sock, n, total;
  1104. #ifdef HAVE_STRUCT_LINGER
  1105.     struct linger li;
  1106. #else
  1107.     int flag_one = 1;
  1108. #endif
  1109.     char buffer[8192];
  1110.     struct stat s;
  1111.  
  1112.     local_handle = open(fe->local_filename, O_RDONLY);
  1113.     unlink (fe->local_filename);
  1114.     if (local_handle == -1) {
  1115.     ftpfserrno = EIO;
  1116.     return 0;
  1117.     }
  1118.     fstat(local_handle, &s);
  1119.     sock = open_data_connection(fe->bucket, "STOR", fe->remote_filename, 1);
  1120.     if (sock < 0) {
  1121.     close(local_handle);
  1122.     return 0;
  1123.     }
  1124. #ifdef HAVE_STRUCT_LINGER
  1125.     li.l_onoff = 1;
  1126.     li.l_linger = 120;
  1127.     setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
  1128. #else
  1129.     setsockopt(sock, SOL_SOCKET, SO_LINGER, &flag_one, sizeof (flag_one));
  1130. #endif
  1131.     total = 0;
  1132.     
  1133.     enable_interrupt_key();
  1134.     while (1) {
  1135.     while ((n = read(local_handle, buffer, sizeof(buffer))) < 0) {
  1136.         if (errno == EINTR) {
  1137.         if (got_interrupt()) {
  1138.             ftpfserrno = EINTR;
  1139.             goto error_return;
  1140.         }
  1141.         else
  1142.             continue;
  1143.         }
  1144.         ftpfserrno = errno;
  1145.         goto error_return;
  1146.     }
  1147.     if (n == 0)
  1148.         break;
  1149.         while (write(sock, buffer, n) < 0) {
  1150.         if (errno == EINTR) {
  1151.         if (got_interrupt()) {
  1152.             ftpfserrno = EINTR;
  1153.             goto error_return;
  1154.         }
  1155.         else 
  1156.             continue;
  1157.         }
  1158.         ftpfserrno = errno;
  1159.         goto error_return;
  1160.     }
  1161.     total += n;
  1162.     print_vfs_message("ftpfs: storing file %d (%d)", 
  1163.               total, s.st_size);
  1164.     }
  1165.     disable_interrupt_key();
  1166.     close(sock);
  1167.     close(local_handle);
  1168.     if (getreply (qsock (fe->bucket), NULL, 0) != COMPLETE) {
  1169.     ftpfserrno = EIO;
  1170.     return 0;
  1171.     }
  1172.     return 1;
  1173. error_return:
  1174.     disable_interrupt_key();
  1175.     close(sock);
  1176.     close(local_handle);
  1177.     getreply(qsock(fe->bucket), NULL, 0);
  1178.     return 0;
  1179. }
  1180.  
  1181. /* These variables are for the _ctl routine */
  1182. static char *localname = NULL;
  1183. static struct ftpentry *remoteent;
  1184. static int remotetotal = 0;
  1185. static int transfer_started = 0;
  1186. static char *remotebuffer;
  1187. static int isremotecopy = 0;
  1188. static int remotelocal_handle, remotesock, remoten, remotestat_size;
  1189.  
  1190. int retrieve_file_start(struct ftpentry *fe)
  1191. {
  1192.     if (fe->local_filename == NULL) {
  1193.     ftpfserrno = ENOMEM;
  1194.     return 0;
  1195.     }
  1196.     remotesock = open_data_connection(fe->bucket, "RETR", fe->remote_filename, 1);
  1197.     if (remotesock == -1) {
  1198.     ftpfserrno = EACCES;
  1199.     free (fe->local_filename);
  1200.     fe->local_filename = NULL;
  1201.     return 0;
  1202.     }
  1203.     remotetotal = 0;
  1204.     remoteent = fe;
  1205.     return 1;
  1206. }
  1207.  
  1208. int retrieve_file_start2(struct ftpentry *fe)
  1209. {
  1210.     remotelocal_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
  1211.     if (remotelocal_handle == -1) {
  1212.     ftpfserrno = EIO;
  1213.     free(fe->local_filename);
  1214.     fe->local_filename = NULL;
  1215.     fe->local_is_temp = 1;
  1216.     close(remotesock);
  1217.     return 0;
  1218.     }
  1219.     remotestat_size = fe->s.st_size;
  1220.     remotebuffer = xmalloc (8192, "");
  1221.     return 1;
  1222. }
  1223.  
  1224. void ftpfs_flushdir ()
  1225. {
  1226.         force_expiration = 1;
  1227. }
  1228.  
  1229. int ftpfs_ctl (void *data, int ctlop, int arg)
  1230. {
  1231.     int n = 0;
  1232.  
  1233.     switch (ctlop) {
  1234.         case MCCTL_ISREMOTECOPY:
  1235.             return isremotecopy;
  1236.         
  1237.         case MCCTL_REMOTECOPYCHUNK:
  1238.             if (!transfer_started)
  1239.                 if (!retrieve_file_start2 (remoteent)){
  1240.                     return MCERR_TARGETOPEN;
  1241.         } else
  1242.             transfer_started = 1;
  1243.  
  1244.         enable_interrupt_key ();
  1245.             if (!remoten) {
  1246.         fd_set set;
  1247.         int v;
  1248.         
  1249.         FD_ZERO (&set);
  1250.         FD_SET (remotesock, &set);
  1251.         FD_SET (0, &set);
  1252.         v = select (remotesock+1, &set, 0, 0, NULL);
  1253.  
  1254.         if (((v < 0) && (errno == EINTR)) || (FD_ISSET (0, &set))){
  1255.             disable_interrupt_key ();
  1256.             return MCERR_DATA_ON_STDIN;
  1257.         }
  1258.             
  1259.                 if ((n = read(remotesock, remotebuffer, 8192)) < 0){
  1260.             disable_interrupt_key ();
  1261.             if (errno == EINTR)
  1262.             return MCERR_DATA_ON_STDIN;
  1263.             else
  1264.             return MCERR_READ;
  1265.         }
  1266.             if (n == 0) {
  1267.                     if (getreply (qsock (remoteent->bucket), NULL, 0) != COMPLETE) {
  1268.                 ftpfserrno = EIO;
  1269.                 }
  1270.                     close(remotelocal_handle);
  1271.                     close(remotesock);
  1272.             if (localname){
  1273.             free (localname);
  1274.             localname = NULL;
  1275.             }
  1276.             disable_interrupt_key ();
  1277.             transfer_started = 0;
  1278.                 return MCERR_FINISH;
  1279.             }
  1280.         disable_interrupt_key ();
  1281.             remotetotal += n;
  1282.             remoten = n;
  1283.             } else
  1284.                 n = remoten;
  1285.             if (write(remotelocal_handle, remotebuffer, remoten) < 0)
  1286.                 return MCERR_WRITE;
  1287.             remoten = 0;
  1288.             return n;
  1289.  
  1290.         /* We get this message if the transfer was aborted */
  1291.         case MCCTL_FINISHREMOTE:
  1292.         if (localname) {
  1293.             free (localname);
  1294.             localname = NULL;
  1295.         }
  1296.         if (!arg) { /* OK */
  1297.             if (stat (remoteent->local_filename, &remoteent->local_stat) < 0)
  1298.                 remoteent->local_stat.st_mtime = 0;
  1299.         } else
  1300.             remoteent->local_stat.st_mtime = 0;
  1301.         transfer_started = 0;
  1302.         ftpfs_abort (remoteent->bucket, remotesock);
  1303.         ftpfserrno = EINTR;
  1304.         return 0;
  1305.     }
  1306.     return 0;
  1307. }
  1308.  
  1309. int ftpfs_setctl (char *path, int ctlop, char *arg)
  1310. {
  1311.     switch (ctlop) {
  1312.         case MCCTL_SETREMOTECOPY: if (localname) free (localname);
  1313.             localname = strdup (vfs_canon (arg));
  1314.             return 1;
  1315.         default:
  1316.             return 0;
  1317.     }
  1318. }
  1319.  
  1320. int retrieve_file(struct ftpentry *fe)
  1321. {
  1322.     int total;
  1323.     char buffer[8192];
  1324.     int local_handle, sock, n;
  1325.     
  1326.     if (fe->local_filename)
  1327.         return 1;
  1328.     fe->local_stat.st_mtime = 0;
  1329.     fe->local_filename = strdup(tmpnam(NULL));
  1330.     fe->local_is_temp = 1;
  1331.     if (fe->local_filename == NULL) {
  1332.     ftpfserrno = ENOMEM;
  1333.     return 0;
  1334.     }
  1335.     local_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
  1336.     if (local_handle == -1) {
  1337.     ftpfserrno = EIO;
  1338.     free(fe->local_filename);
  1339.     fe->local_filename = NULL;
  1340.     return 0;
  1341.     }
  1342.     sock = open_data_connection(fe->bucket, "RETR", fe->remote_filename, 1);
  1343.     if (sock == -1) {
  1344.     ftpfserrno = EACCES;
  1345.     goto error_3;
  1346.     }
  1347.  
  1348.     /* Clear the interrupt status */
  1349.     enable_interrupt_key ();
  1350.     total = 0;
  1351.     while (1) {
  1352.     int stat_size = fe->s.st_size;
  1353.     while ((n = read(sock, buffer, sizeof(buffer))) < 0) {
  1354.         if (errno == EINTR) {
  1355.         if (got_interrupt ()) {
  1356.             disable_interrupt_key();
  1357.             ftpfs_abort(fe->bucket, sock);
  1358.             ftpfserrno = EINTR;
  1359.             goto error_2;
  1360.         }
  1361.         else 
  1362.             continue;
  1363.         }
  1364.         ftpfserrno = errno;
  1365.         disable_interrupt_key();
  1366.         goto error_1;
  1367.     }
  1368.     if (n == 0)
  1369.         break;
  1370.     total += n;
  1371.     if (stat_size == 0)
  1372.         print_vfs_message ("ftpfs: Getting file: %ld bytes transfered", 
  1373.                    total);
  1374.     else
  1375.         print_vfs_message ("ftpfs: Getting file: %3d%% (%ld bytes transfered)",
  1376.                    total*100/stat_size, total);
  1377.         while (write(local_handle, buffer, n) < 0) {
  1378.         if (errno == EINTR) {
  1379.         if (got_interrupt()) {
  1380.             ftpfs_abort(fe->bucket, sock);
  1381.             ftpfserrno = EINTR;
  1382.             goto error_2;
  1383.         }
  1384.         else
  1385.             continue;
  1386.         }
  1387.         ftpfserrno = errno;
  1388.         goto error_1;
  1389.     }
  1390.     }
  1391.     close(local_handle);
  1392.     close(sock);
  1393.     if (getreply (qsock (fe->bucket), NULL, 0) != COMPLETE) {
  1394.     ftpfserrno = EIO;
  1395.     goto error_2;
  1396.     }
  1397.     if (stat (fe->local_filename, &fe->local_stat) < 0)
  1398.         fe->local_stat.st_mtime = 0;
  1399.     return 1;
  1400. error_1:
  1401.     getreply(qsock(fe->bucket), NULL, 0);
  1402. error_2:
  1403.     close(sock);
  1404. error_3:
  1405.     disable_interrupt_key ();
  1406.     close(local_handle);
  1407.     unlink(fe->local_filename);
  1408.     free(fe->local_filename);
  1409.     fe->local_filename = NULL;
  1410.     return 0;
  1411. }
  1412.  
  1413. static struct ftpentry *
  1414. _get_file_entry(struct ftpfs_connection *bucket, char *file_name, 
  1415.         int op, int flags)
  1416. {
  1417.     char *p, q;
  1418.     struct ftpentry *ent;
  1419.     struct linklist *file_list, *lptr;
  1420.     struct ftpfs_dir *dcache;
  1421.     struct stat sb;
  1422.  
  1423.     p = strrchr(file_name, '/');
  1424.     q = *p;
  1425.     *p = '\0';
  1426.     dcache = retrieve_dir(bucket, *file_name ? file_name : "/");
  1427.     if (dcache == NULL)
  1428.         return NULL;
  1429.     file_list = dcache->file_list;
  1430.     *p++ = q;
  1431.     if (!*p) 
  1432.         p = ".";
  1433.     for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
  1434.     ent = lptr->data;
  1435.         if (strcmp(p, ent->name) == 0) {
  1436.         if (S_ISLNK(ent->s.st_mode) && (op & FTPFS_RESOLVE_SYMLINK)) {
  1437.         if (ent->l_stat == NULL) {
  1438.             ftpfserrno = ENOENT;
  1439.             return NULL;
  1440.         }
  1441.         if (S_ISLNK(ent->l_stat->st_mode)) {
  1442.             ftpfserrno = ELOOP;
  1443.             return NULL;
  1444.         }
  1445.         }
  1446.         if (ent && (op & FTPFS_OPEN)) {
  1447.         mode_t fmode;
  1448.  
  1449.         fmode = S_ISLNK(ent->s.st_mode)
  1450.             ? ent->l_stat->st_mode
  1451.             : ent->s.st_mode;
  1452.         if (S_ISDIR(fmode)) {
  1453.             ftpfserrno = EISDIR;
  1454.             return NULL;
  1455.         }
  1456.         if (!S_ISREG(fmode)) {
  1457.             ftpfserrno = EPERM;
  1458.             return NULL;
  1459.         }
  1460.         if ((flags & O_EXCL) && (flags & O_CREAT)) {
  1461.             ftpfserrno = EEXIST;
  1462.             return NULL;
  1463.         }
  1464.         if (ent->remote_filename == NULL) {
  1465.             ent->remote_filename = strdup(file_name);
  1466.             if (ent->remote_filename == NULL) {
  1467.             ftpfserrno = ENOMEM;
  1468.             return NULL;
  1469.             }
  1470.         }
  1471.         if (ent->local_filename == NULL || 
  1472.             !ent->local_stat.st_mtime || 
  1473.             stat (ent->local_filename, &sb) < 0 || 
  1474.             sb.st_mtime != ent->local_stat.st_mtime) {
  1475.             int handle;
  1476.             
  1477.             if (ent->local_filename){
  1478.                 free (ent->local_filename);
  1479.             ent->local_filename = 0;
  1480.             }
  1481.             if (flags & O_TRUNC) {
  1482.             ent->local_filename = strdup(tmpnam(NULL));
  1483.             if (ent->local_filename == NULL) {
  1484.                 ftpfserrno = ENOMEM;
  1485.                 return NULL;
  1486.             }
  1487.             handle = open(ent->local_filename, O_CREAT | O_TRUNC | 
  1488.                  O_RDWR, 0600);
  1489.             if (handle < 0) {
  1490.                 ftpfserrno = EIO;
  1491.                 return NULL;
  1492.             }
  1493.             close(handle);
  1494.             if (stat (ent->local_filename, &ent->local_stat) < 0)
  1495.                 ent->local_stat.st_mtime = 0;
  1496.             }
  1497.             else {
  1498.                 if (localname != NULL) {
  1499.                     isremotecopy = 1;
  1500.                     ent->local_is_temp = 0;
  1501.                     ent->local_stat.st_mtime = 0;
  1502.                     ent->local_filename = strdup (localname);
  1503.                     if (!retrieve_file_start (ent)) {
  1504.                         isremotecopy = 0;
  1505.                         return NULL;
  1506.                     }
  1507.                     return ent;
  1508.                 }
  1509.                 if (!retrieve_file(ent))
  1510.                 return NULL;
  1511.             }
  1512.         }
  1513.         else if (flags & O_TRUNC) {
  1514.             truncate(ent->local_filename, 0);
  1515.         }
  1516.         }
  1517.         return ent;
  1518.     }
  1519.     }
  1520.     if ((op & FTPFS_OPEN) && (flags & O_CREAT)) {
  1521.     int handle;
  1522.  
  1523.     ent = xmalloc(sizeof(struct ftpentry), "struct ftpentry");
  1524.     ent->freshly_created = 0;
  1525.     if (ent == NULL) {
  1526.         ftpfserrno = ENOMEM;
  1527.         return NULL;
  1528.     }
  1529.     ent->count = 1;
  1530.     ent->linkname = NULL;
  1531.     ent->l_stat = NULL;
  1532.     ent->bucket = bucket;
  1533.     ent->name = strdup(p);
  1534.     ent->remote_filename = strdup(file_name);
  1535.     ent->local_filename = strdup(tmpnam(NULL));
  1536.     if (!ent->name && !ent->remote_filename && !ent->local_filename) {
  1537.         ftpentry_destructor(ent);
  1538.         ftpfserrno = ENOMEM;
  1539.         return NULL;
  1540.     }
  1541.         handle = creat(ent->local_filename, 0700);
  1542.     if (handle == -1) {
  1543.         ftpfserrno = EIO;
  1544.         ftpentry_destructor(ent);
  1545.         return NULL;
  1546.     }
  1547.     fstat(handle, &ent->s);
  1548.     close(handle);
  1549. #if 0
  1550. /* This is very wrong - like this a zero length file will be always created
  1551.    and usually preclude uploading anything more desirable */    
  1552. #if defined(UPLOAD_ZERO_LENGTH_FILE)
  1553.     if (!store_file(ent)) {
  1554.         ftpentry_destructor(ent);
  1555.         return NULL;
  1556.     }
  1557. #endif
  1558. #endif
  1559.     if (!linklist_insert(file_list, ent)) {
  1560.         ftpfserrno = ENOMEM;
  1561.         ftpentry_destructor(ent);
  1562.         return NULL;
  1563.     }
  1564.     ent->freshly_created = 1;
  1565.     return ent;
  1566.     }
  1567.     else {
  1568.     ftpfserrno = ENOENT;
  1569.     return NULL;
  1570.     }
  1571. }
  1572.  
  1573. static struct ftpentry *
  1574. get_file_entry(char *path, int op, int flags)
  1575. {
  1576.     struct ftpfs_connection *bucket;
  1577.     struct ftpentry *fe;
  1578.     char *remote_path;
  1579.  
  1580.     if (!(remote_path = ftpfs_get_path (&bucket, path)))
  1581.     return NULL;
  1582.     isremotecopy = 0;
  1583.     fe = _get_file_entry(bucket, remote_path, op,
  1584.              flags);
  1585.     free(remote_path);
  1586.     if (op & FTPFS_FREE_RESOURCE)
  1587.     vfs_add_noncurrent_stamps (&ftpfs_vfs_ops, (vfsid) bucket, NULL);
  1588.     return fe;
  1589. }
  1590.  
  1591. #define OPT_FLUSH        1
  1592. #define OPT_IGNORE_ERROR 2
  1593.  
  1594. static int ftpfs_normal_flush = 1;
  1595.  
  1596. void ftpfs_hint_reread(int reread)
  1597. {
  1598.     if (reread)
  1599.     ftpfs_normal_flush++;
  1600.     else
  1601.     ftpfs_normal_flush--;
  1602. }
  1603.  
  1604. static int
  1605. send_ftp_command(char *filename, char *cmd, int flags)
  1606. {
  1607.     char *remote_path;
  1608.     struct ftpfs_connection *bucket;
  1609.     int r;
  1610.     int flush_directory_cache = (flags & OPT_FLUSH) && (ftpfs_normal_flush > 0);
  1611.  
  1612.     if (!(remote_path = ftpfs_get_path(&bucket, filename)))
  1613.     return -1;
  1614.     r = command (bucket, WAIT_REPLY, cmd, remote_path);
  1615.     free(remote_path);
  1616.     vfs_add_noncurrent_stamps (&ftpfs_vfs_ops, (vfsid) bucket, NULL);
  1617.     if (flags & OPT_IGNORE_ERROR)
  1618.     r = COMPLETE;
  1619.     if (r != COMPLETE) {
  1620.     ftpfserrno = EPERM;
  1621.     return -1;
  1622.     }
  1623.     if (flush_directory_cache)
  1624.     flush_all_directory(bucket);
  1625.     return 0;
  1626. }
  1627.  
  1628. /* This routine is called as the last step in load_setup */
  1629. void
  1630. ftpfs_init_passwd(void)
  1631. {
  1632.     struct passwd *passwd_info;
  1633.     char *p, hostname[MAXHOSTNAMELEN];
  1634.     struct hostent *hp;
  1635.  
  1636.     ftpfs_anonymous_passwd = load_anon_passwd ();
  1637.     if (ftpfs_anonymous_passwd)
  1638.     return;
  1639.  
  1640.     if ((passwd_info = getpwuid (geteuid ())) == NULL)
  1641.     p = "guest";
  1642.     else
  1643.     p = passwd_info->pw_name;
  1644.     gethostname(hostname, sizeof(hostname));
  1645.     hp = gethostbyname(hostname);
  1646.     if (hp != NULL)
  1647.     ftpfs_anonymous_passwd = copy_strings (p, "@", hp->h_name, NULL);
  1648.     else
  1649.     ftpfs_anonymous_passwd = copy_strings (p, "@", hostname, NULL);
  1650.     endpwent ();
  1651. }
  1652.  
  1653. void
  1654. ftpfs_init ()
  1655. {
  1656.     ftpfs_connections_list = linklist_init();
  1657.     ftpfs_directory_timeout = FTPFS_DIRECTORY_TIMEOUT;
  1658. }
  1659.  
  1660. void
  1661. ftpfs_done(void)
  1662. {
  1663.     linklist_destroy(ftpfs_connections_list, ftpfs_connection_destructor);
  1664. }
  1665.  
  1666. /* The callbacks */
  1667.  
  1668. struct ftpfs_filp {
  1669.     unsigned int has_changed:1;
  1670.     struct ftpentry *fe;
  1671.     int local_handle;
  1672. };
  1673.  
  1674. static void *ftpfs_open (char *file, int flags, int mode)
  1675. {
  1676.     struct ftpfs_filp *fp;
  1677.     struct ftpentry *fe;
  1678.  
  1679.     fp = xmalloc(sizeof(struct ftpfs_filp), "struct ftpfs_filp");
  1680.     if (fp == NULL) {
  1681.     ftpfserrno = ENOMEM;
  1682.         return NULL;
  1683.     }
  1684.     fe = get_file_entry(file, FTPFS_OPEN | FTPFS_RESOLVE_SYMLINK, flags);
  1685.     if (fe == NULL) {
  1686.     free(fp);
  1687.         return NULL;
  1688.     }
  1689.     if (!isremotecopy) {
  1690.         fp->local_handle = open(fe->local_filename, flags, mode);
  1691.         if (fp->local_handle < 0) {
  1692.         ftpfserrno = errno;
  1693.         free(fp);
  1694.         return NULL;
  1695.         }
  1696.     } else
  1697.         fp->local_handle = -1;
  1698. #ifdef UPLOAD_ZERO_LENGTH_FILE        
  1699.     fp->has_changed = fe->freshly_created;
  1700. #else
  1701.     fp->has_changed = 0;
  1702. #endif    
  1703.     fp->fe = fe;
  1704.     qlock(fe->bucket)++;
  1705.     fe->count++;
  1706.     return fp;
  1707. }
  1708.  
  1709. static int ftpfs_read (void *data, char *buffer, int count)
  1710. {
  1711.     struct ftpfs_filp *fp;
  1712.     int n;
  1713.     
  1714.     fp = data;
  1715.     n = read(fp->local_handle, buffer, count);
  1716.     if (n < 0)
  1717.       ftpfserrno = errno;
  1718.     return n;
  1719. }
  1720.  
  1721. int ftpfs_write (void *data, char *buf, int nbyte)
  1722. {
  1723.     struct ftpfs_filp *fp;
  1724.     int n;
  1725.     
  1726.     fp = data;
  1727.     n = write(fp->local_handle, buf, nbyte);
  1728.     if (n < 0)
  1729.       ftpfserrno = errno;
  1730.     fp->has_changed = 1;
  1731.     return n;
  1732. }
  1733.  
  1734. static int ftpfs_close (void *data)
  1735. {
  1736.     struct ftpfs_filp *fp = data;
  1737.     int result = 0;
  1738.  
  1739.     if (fp->has_changed) {
  1740.     if (!store_file(fp->fe)) {
  1741.         ftpfserrno = EIO;
  1742.         result = -1;
  1743.     }
  1744.     flush_all_directory(fp->fe->bucket);
  1745.     }
  1746.     if (fp->local_handle >= 0)
  1747.         close(fp->local_handle);
  1748.     qlock(fp->fe->bucket)--;
  1749.     ftpentry_destructor(fp->fe);
  1750.     free(fp);
  1751.     return result;
  1752. }
  1753.  
  1754. static int ftpfs_errno (void)
  1755. {
  1756.     return ftpfserrno;
  1757. }
  1758.  
  1759.  
  1760. /* Explanation:
  1761.  * On some operating systems (Slowaris 2 for example)
  1762.  * the d_name member is just a char long (Nice trick that break everything,
  1763.  * so we need to set up some space for the filename.
  1764.  */
  1765. struct ftpfs_dirent {
  1766.     struct dirent dent;
  1767. #ifdef NEED_EXTRA_DIRENT_BUFFER
  1768.     char extra_buffer [MC_MAXPATHLEN];
  1769. #endif
  1770.     struct linklist *pos;
  1771.     struct ftpfs_dir *dcache;
  1772. };
  1773.  
  1774. char *ftpfs_gethome (char *servername)
  1775. {
  1776.     struct ftpfs_connection *bucket;
  1777.     char *remote_path;
  1778.  
  1779.     if (!(remote_path = ftpfs_get_path (&bucket, servername)))
  1780.         return NULL;
  1781.     free (remote_path);
  1782.     return qhome(bucket);
  1783. }
  1784.  
  1785. char *ftpfs_getupdir (char *servername)
  1786. {
  1787.     struct ftpfs_connection *bucket;
  1788.     char *remote_path;
  1789.  
  1790.     if (!(remote_path = ftpfs_get_path (&bucket, servername)))
  1791.         return NULL;
  1792.     free (remote_path);
  1793.     return qupdir(bucket);
  1794. }
  1795.  
  1796. static void *ftpfs_opendir (char *dirname)
  1797. {
  1798.     struct ftpfs_connection *bucket;
  1799.     char *remote_path;
  1800.     struct ftpfs_dirent *dirp;
  1801.  
  1802.     if (!(remote_path = ftpfs_get_path (&bucket, dirname)))
  1803.         return NULL;
  1804.     dirp = xmalloc(sizeof(struct ftpfs_dirent), "struct ftpfs_dirent");
  1805.     if (dirp == NULL) {
  1806.     ftpfserrno = ENOMEM;
  1807.     goto error_return;
  1808.     }
  1809.     dirp->dcache = retrieve_dir(bucket, remote_path);
  1810.     if (dirp->dcache == NULL)
  1811.         goto error_return;
  1812.     dirp->pos = dirp->dcache->file_list->next;
  1813.     free(remote_path);
  1814.     dirp->dcache->count++;
  1815.     return (void *)dirp;
  1816. error_return:
  1817.     vfs_add_noncurrent_stamps (&ftpfs_vfs_ops, (vfsid) bucket, NULL);
  1818.     free(remote_path);
  1819.     free(dirp);
  1820.     return NULL;
  1821. }
  1822.  
  1823. static void *ftpfs_readdir (void *data)
  1824. {
  1825.     struct ftpentry *fe;
  1826.     struct ftpfs_dirent *dirp = data;
  1827.     
  1828.     if (dirp->pos == dirp->dcache->file_list)
  1829.     return NULL;
  1830.     fe = dirp->pos->data;
  1831.     strcpy (&(dirp->dent.d_name [0]), fe->name);
  1832. #ifndef DIRENT_LENGTH_COMPUTED
  1833.     dirp->d_namlen = strlen (dirp->d_name);
  1834. #endif
  1835.     dirp->pos = dirp->pos->next;
  1836.     return (void *) &dirp->dent;
  1837. }
  1838.  
  1839. static int ftpfs_closedir (void *info)
  1840. {
  1841.     struct ftpfs_dirent *dirp = info;
  1842.     ftpfs_dir_destructor(dirp->dcache);
  1843.     free(dirp);
  1844.     return 0;
  1845. }
  1846.  
  1847. static int ftpfs_lstat (char *path, struct stat *buf)
  1848. {
  1849.     struct ftpentry *fe;
  1850.     
  1851.     fe = get_file_entry(path, FTPFS_FREE_RESOURCE, 0);
  1852.     if (fe) {
  1853.     *buf = fe->s;
  1854.     return 0;
  1855.     }
  1856.     else
  1857.         return -1;
  1858. }
  1859.  
  1860. static int ftpfs_stat (char *path, struct stat *buf)
  1861. {
  1862.     struct ftpentry *fe;
  1863.  
  1864.     fe = get_file_entry(path, FTPFS_RESOLVE_SYMLINK | FTPFS_FREE_RESOURCE, 0);
  1865.     if (fe) {
  1866.     if (!S_ISLNK(fe->s.st_mode))
  1867.         *buf = fe->s;
  1868.     else
  1869.         *buf = *fe->l_stat;
  1870.     return 0;
  1871.     }
  1872.     else
  1873.         return -1;
  1874. }
  1875.  
  1876. int ftpfs_fstat (void *data, struct stat *buf)
  1877. {
  1878.     struct ftpfs_filp *fp = data;
  1879.  
  1880.     if (!S_ISLNK(fp->fe->s.st_mode))
  1881.     *buf = fp->fe->s;
  1882.     else
  1883.     *buf = *fp->fe->l_stat;
  1884.     return 0;
  1885. }
  1886.  
  1887. int ftpfs_chmod (char *path, int mode)
  1888. {
  1889.     char buf[40];
  1890.     
  1891.     sprintf(buf, "SITE CHMOD %4.4o %%s", mode & 07777);
  1892.     return send_ftp_command(path, buf, OPT_IGNORE_ERROR | OPT_FLUSH);
  1893. }
  1894.  
  1895. int ftpfs_chown (char *path, int owner, int group)
  1896. {
  1897. #if 0
  1898.     ftpfserrno = EPERM;
  1899.     return -1;
  1900. #else
  1901. /* Everyone knows it is not possible to chown remotely, so why bother them.
  1902.    If someone's root, then copy/move will always try to chown it... */
  1903.     return 0;
  1904. #endif    
  1905. }
  1906.  
  1907. static int ftpfs_readlink (char *path, char *buf, int size)
  1908. {
  1909.     struct ftpentry *fe;
  1910.  
  1911.     fe = get_file_entry(path, FTPFS_FREE_RESOURCE, 0);
  1912.     if (!fe)
  1913.     return -1;
  1914.     if (!S_ISLNK(fe->s.st_mode)) {
  1915.     ftpfserrno = EINVAL;
  1916.     return -1;
  1917.     }
  1918.     if (fe->linkname == NULL) {
  1919.     ftpfserrno = EACCES;
  1920.     return -1;
  1921.     }
  1922.     if (strlen(fe->linkname) >= size) {
  1923.     ftpfserrno = ERANGE;
  1924.     return -1;
  1925.     }
  1926.     strncpy(buf, fe->linkname, size);
  1927.     return strlen(fe->linkname);
  1928. }
  1929.  
  1930. static int ftpfs_unlink (char *path)
  1931. {
  1932.     return send_ftp_command(path, "DELE %s", 1);
  1933. }
  1934.  
  1935. static int ftpfs_symlink (char *n1, char *n2)
  1936. {
  1937.     ftpfserrno = EPERM;
  1938.     return -1;
  1939. }
  1940.  
  1941. static int ftpfs_rename (char *path1, char *path2)
  1942. {
  1943.     ftpfserrno = EPERM;
  1944.     return -1;
  1945. }
  1946.  
  1947. static int ftpfs_chdir (char *path)
  1948. {
  1949.     char *remote_path;
  1950.     struct ftpfs_connection *bucket;
  1951.     int r;
  1952.  
  1953.  retry:
  1954.     if (!(remote_path = ftpfs_get_path(&bucket, path)))
  1955.     return -1;
  1956.     got_sigpipe = 0;
  1957.     r = command (bucket, WAIT_REPLY, "CWD %s", remote_path);
  1958.     if (got_sigpipe)
  1959.     goto retry;
  1960.  
  1961.     if (r != COMPLETE) {
  1962.     ftpfserrno = EIO;
  1963.         free(remote_path);
  1964.     } else {
  1965.         if (qcdir(bucket))
  1966.         free(qcdir(bucket));
  1967.     qcdir(bucket) = remote_path;
  1968.     }
  1969.     vfs_add_noncurrent_stamps (&ftpfs_vfs_ops, (vfsid) bucket, NULL);
  1970.     return r == COMPLETE ? 0 : -1;
  1971. }
  1972.  
  1973. static int ftpfs_lseek (void *data, off_t offset, int whence)
  1974. {
  1975.     struct ftpfs_filp *fp = data;
  1976.  
  1977.     return lseek(fp->local_handle, offset, whence);
  1978. }
  1979.  
  1980. static int ftpfs_mknod (char *path, int mode, int dev)
  1981. {
  1982.     ftpfserrno = EPERM;
  1983.     return -1;
  1984. }
  1985.  
  1986. static int ftpfs_mkdir (char *path, mode_t mode)
  1987. {
  1988.     return send_ftp_command(path, "MKD %s", 1);
  1989. }
  1990.  
  1991. static int ftpfs_rmdir (char *path)
  1992. {
  1993.     return send_ftp_command(path, "RMD %s", 1);
  1994. }
  1995.  
  1996. static int ftpfs_link (char *p1, char *p2)
  1997. {
  1998.     ftpfserrno = EPERM;
  1999.     return -1;
  2000. }
  2001.  
  2002. static vfsid ftpfs_getid (char *p, struct vfs_stamping **parent)
  2003. {
  2004.     struct ftpfs_connection *bucket;
  2005.     char *remote_path;
  2006.  
  2007.     *parent = NULL; /* We are not enclosed in any other fs */
  2008.     
  2009.     if (!(remote_path = ftpfs_get_path (&bucket, p)))
  2010.         return (vfsid) -1;
  2011.     else {
  2012.     free(remote_path);
  2013.         return (vfsid) bucket;
  2014.     }
  2015. }
  2016.  
  2017. static int ftpfs_nothingisopen (vfsid id)
  2018. {
  2019.     return qlock((struct ftpfs_connection *)id) == 0;
  2020. }
  2021.  
  2022. static void ftpfs_free (vfsid id)
  2023. {
  2024.     struct ftpfs_connection *bucket = (struct ftpfs_connection *) id;
  2025.  
  2026.     ftpfs_connection_destructor(bucket);
  2027.     linklist_delete(ftpfs_connections_list, bucket);
  2028. }
  2029.  
  2030. static char *ftpfs_getlocalcopy (char *path)
  2031. {
  2032.     struct ftpfs_filp *fp = (struct ftpfs_filp *) ftpfs_open (path, O_RDONLY, 0);
  2033.     char *p;
  2034.     
  2035.     if (fp == NULL)
  2036.         return NULL;
  2037.     if (fp->fe->local_filename == NULL) {
  2038.         ftpfs_close ((void *) fp);
  2039.         return NULL;
  2040.     }
  2041.     p = strdup (fp->fe->local_filename);
  2042.     qlock(fp->fe->bucket)++;
  2043.     fp->fe->count++;
  2044.     ftpfs_close ((void *) fp);
  2045.     return p;
  2046. }
  2047.  
  2048. static void ftpfs_ungetlocalcopy (char *path, char *local, int has_changed)
  2049. {
  2050.     struct ftpfs_filp *fp = (struct ftpfs_filp *) ftpfs_open (path, O_WRONLY, 0);
  2051.     
  2052.     if (fp == NULL)
  2053.         return;
  2054.     if (!strcmp (fp->fe->local_filename, local)) {
  2055.         fp->has_changed = has_changed;
  2056.         qlock(fp->fe->bucket)--;
  2057.         ftpentry_destructor(fp->fe);
  2058.         ftpfs_close ((void *) fp);
  2059.     } else {
  2060.         /* Should not happen */
  2061.         ftpfs_close ((void *) fp);
  2062.         mc_def_ungetlocalcopy (path, local, has_changed);
  2063.     }
  2064. }
  2065.  
  2066. void ftpfs_set_debug (char *file)
  2067. {
  2068.     if ((ftpfs_logfile = fopen (file, "w+")) != NULL)
  2069.     ftpfs_debug_server_dialog = 1;
  2070. }
  2071.  
  2072. #ifdef HAVE_MMAP
  2073. caddr_t ftpfs_mmap (caddr_t addr, size_t len, int prot, int flags, void *data, off_t offset)
  2074. {
  2075.     return (caddr_t)-1; /* We do not mmap to far away */
  2076. }
  2077.  
  2078. int ftpfs_munmap (caddr_t addr, size_t len, void *data)
  2079. {
  2080.     return -1;
  2081. }
  2082. #endif
  2083.  
  2084. vfs ftpfs_vfs_ops = {
  2085.     ftpfs_open,
  2086.     ftpfs_close,
  2087.     ftpfs_read,
  2088.     ftpfs_write,
  2089.     
  2090.     ftpfs_opendir,
  2091.     ftpfs_readdir,
  2092.     ftpfs_closedir,
  2093.  
  2094.     ftpfs_stat,
  2095.     ftpfs_lstat,
  2096.     ftpfs_fstat,
  2097.  
  2098.     ftpfs_chmod,
  2099.     ftpfs_chown,
  2100.  
  2101.     ftpfs_readlink,
  2102.     ftpfs_symlink,
  2103.     ftpfs_link,
  2104.     ftpfs_unlink,
  2105.  
  2106.     ftpfs_rename,
  2107.     ftpfs_chdir,
  2108.     ftpfs_errno,
  2109.     ftpfs_lseek,
  2110.     ftpfs_mknod,
  2111.     
  2112.     ftpfs_getid,
  2113.     ftpfs_nothingisopen,
  2114.     ftpfs_free,
  2115.     
  2116.     ftpfs_getlocalcopy,
  2117.     ftpfs_ungetlocalcopy,
  2118.  
  2119.     ftpfs_mkdir,
  2120.     ftpfs_rmdir,
  2121.     ftpfs_ctl,
  2122.     ftpfs_setctl
  2123. #ifdef HAVE_MMAP
  2124.     , ftpfs_mmap,
  2125.     ftpfs_munmap
  2126. #endif
  2127. };
  2128.  
  2129. #ifdef USE_NETRC
  2130. static char buffer[100];
  2131. static char *netrc, *netrcp;
  2132.  
  2133. static int netrc_next (void)
  2134. {
  2135.     char *p;
  2136.     int i;
  2137.     static char *keywords [] = { "default", "machine", 
  2138.         "login", "password", "passwd",
  2139.         "account", "macdef" };
  2140.  
  2141.     while (1) {
  2142.         netrcp = skip_separators (netrcp);
  2143.         if (*netrcp != '\n')
  2144.             break;
  2145.         netrcp++;
  2146.     }
  2147.     if (!*netrcp)
  2148.     return 0;
  2149.     p = buffer;
  2150.     if (*netrcp == '"') {
  2151.     for (;*netrcp != '"' && *netrcp; netrcp++) {
  2152.         if (*netrcp == '\\')
  2153.         netrcp++;
  2154.         *p++ = *netrcp;
  2155.     }
  2156.     } else {
  2157.     for (;*netrcp != '\n' && *netrcp != '\t' && *netrcp != ' ' &&
  2158.         *netrcp != ',' && *netrcp; netrcp++) {
  2159.         if (*netrcp == '\\')
  2160.         netrcp++;
  2161.         *p++ = *netrcp;
  2162.     }
  2163.     }
  2164.     *p = 0;
  2165.     if (!*buffer)
  2166.     return 0;
  2167.     for (i = 0; i < sizeof (keywords) / sizeof (keywords [0]); i++)
  2168.     if (!strcmp (keywords [i], buffer))
  2169.         break;
  2170.     return i + 1;
  2171. }
  2172.  
  2173. int lookup_netrc (char *host, char **login, char **pass)
  2174. {
  2175.     char *netrcname, *tmp;
  2176.     char hostname[MAXHOSTNAMELEN], *domain;
  2177.     int c, d, keyword;
  2178.     struct stat mystat;
  2179.     static int be_angry = 1;
  2180.     static struct rupcache {
  2181.         struct rupcache *next;
  2182.         char *host;
  2183.         char *login;
  2184.         char *pass;
  2185.     } *rup_cache = NULL, *rupp;
  2186.  
  2187.     for (rupp = rup_cache; rupp != NULL; rupp = rupp->next)
  2188.         if (!strcmp (host, rupp->host)) {
  2189.             if (rupp->login != NULL)
  2190.                 *login = strdup (rupp->login);
  2191.             if (rupp->pass != NULL)
  2192.                 *pass = strdup (rupp->pass);
  2193.             return 0;
  2194.         }
  2195.     netrcname = xmalloc (strlen (home_dir) + strlen ("/.netrc") + 1, "netrc");
  2196.     strcpy (netrcname, home_dir);
  2197.     strcat (netrcname, "/.netrc");
  2198.     netrcp = netrc = load_file (netrcname);
  2199.     if (netrc == NULL) {
  2200.         free (netrcname);
  2201.     return 0;
  2202.     }
  2203.     if (gethostname (hostname, sizeof (hostname)) < 0)
  2204.     *hostname = 0;
  2205.     if (!(domain = strchr (hostname, '.')))
  2206.     domain = "";
  2207.  
  2208.     while ((keyword = netrc_next ())) {
  2209.         if (keyword == 2) {
  2210.         if (netrc_next () != 8)
  2211.         continue;
  2212.         if (strcasecmp (host, buffer) &&
  2213.             ((tmp = strchr (host, '.')) == NULL ||
  2214.         strcasecmp (tmp, domain) ||
  2215.         strncasecmp (host, buffer, tmp - host) ||
  2216.         buffer [tmp - host]))
  2217.         continue;
  2218.     } else if (keyword != 1)
  2219.         continue;
  2220.     while ((keyword = netrc_next ()) > 2) {
  2221.         switch (keyword) {
  2222.         case 3:
  2223.             if (netrc_next ())
  2224.             if (*login == NULL)
  2225.                 *login = strdup (buffer);
  2226.             else if (strcmp (*login, buffer))
  2227.                 keyword = 20;
  2228.             break;
  2229.         case 4:
  2230.         case 5:
  2231.             if (strcmp (*login, "anonymous") && strcmp (*login, "ftp") &&
  2232.             stat (netrcname, &mystat) >= 0 &&
  2233.             (mystat.st_mode & 077)) {
  2234.             if (be_angry) {
  2235.                 message (1, "Error", "~/.netrc file has not correct mode.\n"
  2236.                              "Remove password or correct mode.");
  2237.                 be_angry = 0;
  2238.             }
  2239.             free (netrc);
  2240.             free (netrcname);
  2241.             return -1;
  2242.             }
  2243.             if (netrc_next () && *pass == NULL)
  2244.             *pass = strdup (buffer);
  2245.             break;
  2246.         case 6:
  2247.             if (stat (netrcname, &mystat) >= 0 && 
  2248.                 (mystat.st_mode & 077)) {
  2249.             if (be_angry) {
  2250.                 message (1, "Error", "~/.netrc file has not correct mode.\n"
  2251.                              "Remove password or correct mode.");
  2252.                 be_angry = 0;
  2253.             }
  2254.             free (netrc);
  2255.             free (netrcname);
  2256.             return -1;
  2257.             }
  2258.             netrc_next ();
  2259.             break;
  2260.         case 7:
  2261.             for (;;) {
  2262.                 while (*netrcp != '\n' && *netrcp);
  2263.                 if (*netrcp != '\n')
  2264.                     break;
  2265.                 netrcp++;
  2266.                 if (*netrcp == '\n' || !*netrcp)
  2267.                     break;
  2268.             }
  2269.             break;
  2270.         }
  2271.         if (keyword == 20)
  2272.             break;
  2273.     }
  2274.     if (keyword == 20)
  2275.         continue;
  2276.     else
  2277.         break;
  2278.     }
  2279.     rupp = (struct rupcache *) xmalloc (sizeof (struct rupcache), "");
  2280.     rupp->host = strdup (host);
  2281.     rupp->login = rupp->pass = 0;
  2282.     
  2283.     if (*login != NULL)
  2284.         rupp->login = strdup (*login);
  2285.     if (*pass != NULL)
  2286.         rupp->pass = strdup (*pass);
  2287.     rupp->next = rup_cache;
  2288.     rup_cache = rupp;
  2289.     
  2290.     free (netrc);
  2291.     free (netrcname);
  2292.     return 0;
  2293. }
  2294.  
  2295. #ifndef HAVE_STRNCASECMP
  2296. int strncasecmp (char *s, char *d, int l)
  2297. {
  2298.     int result;
  2299.     
  2300.     while (l--){
  2301.     if (result = (0x20 | *s) - (0x20 | *d))
  2302.         break;
  2303.     if (!*s)
  2304.         return 0;
  2305.     s++;
  2306.     d++;
  2307.     }
  2308. }
  2309. #endif
  2310. #endif /* USE_NETRC */
  2311.